﻿using ComponentFactory.Krypton.Toolkit;
using StableDiffusionTools.AUTOMATIC1111;
using StableDiffusionTools.Forms;
using StableDiffusionTools.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Forms;
using TaggingToolkit.Events;
using TaggingToolkit.Framework;

namespace TaggingToolkit.Forms
{
    public partial class SettingsForm : KryptonForm
    {
        private HSLColorPickerForm hsl = new HSLColorPickerForm();
        private TaggingToolkitSettings settings;
        private bool loading = false;
        private APIStatus lastStatus = APIStatus.Unknown;
        private Control lastActiveControl = null;
        TaggingToolkitForm taggingTookkit;
        public bool FetchedSettings { get; private set; } = false;

        public SettingsForm(TaggingToolkitSettings initialSettings, TaggingToolkitForm taggingForm)
        {
            InitializeComponent();

            Icon = Properties.Resources.gear_icon;

            settings = initialSettings;
            taggingTookkit = taggingForm;

            kryptonNUDPort.Value = settings.WebUIPort;

            pbStatus.Image = StableDiffusionTools.Properties.Resources.bullet_black16;
            toolTip1.SetToolTip(pbStatus, "Unknown");
            Load += (s, e) =>
            {
                if (Owner != null)
                {
                    CenterToParent();
                }
            };

            kryptonNUDPort.ValueChanged += (s, e) =>
            {
                WebUIAPI.WebUIPort = settings.WebUIPort = (int)kryptonNUDPort.Value;
            };

            kryptonCHKKeepModelsInVRAM.CheckedChanged += (s, e) =>
            {
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonTBNumBeams.ValueChanged += (s, e) =>
            {
                kryptonLBLNumBeams.Text = $"Num Beams: {kryptonTBNumBeams.Value}";
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonTBMinLength.ValueChanged += (s, e) =>
            {
                kryptonLBLMinLength.Text = $"Min Length: {kryptonTBMinLength.Value}";
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonTBMaxLength.ValueChanged += (s, e) =>
            {
                kryptonLBLMaxLength.Text = $"Max Lenth: {kryptonTBMaxLength.Value}";
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonCHKSortByAlpha.CheckedChanged += (s, e) =>
            {
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonCHKUseSpaces.CheckedChanged += (s, e) =>
            {
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonCHKEscape.CheckedChanged += (s, e) =>
            {
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            kryptonTBThreshold.ValueChanged += (s, e) =>
            {
                kryptonLBLThreshold.Text = $"Threshold: {kryptonTBThreshold.Value / 100f:0.00}";
                if (loading)
                    return;
                kryptonBTNSave.Enabled = true;
            };

            int selectedIndex = 0;
            Size[] sizes = { new Size(16, 16), new Size(24, 24), new Size(32, 32), new Size(64, 64), new Size(128, 128) };
            for (int i = 0; i < sizes.Length; i++)
            {
                kryptonCMBThumbnailSize.Items.Add($"{sizes[i].Width}x{sizes[i].Height}");
                if (settings.PreviewSize == sizes[i].Width)
                {
                    selectedIndex = i;
                }
            }
            kryptonCMBThumbnailSize.SelectedIndex = selectedIndex;
            kryptonCMBThumbnailSize.SelectedIndexChanged += (s, e) =>
            {
                settings.PreviewSize = sizes[kryptonCMBThumbnailSize.SelectedIndex].Width;
                taggingForm.SetImagePreviews(settings.DisplayImageThumbnails, settings.PreviewSize);
            };

            kryptonCHKShowThumbnails.Checked = settings.DisplayImageThumbnails;
            kryptonCHKShowThumbnails.CheckedChanged += (s, e) =>
            {
                settings.DisplayImageThumbnails = kryptonCHKShowThumbnails.Checked;
                kryptonCHKFitFileColumnToThumbnails.Enabled = kryptonCHKShowThumbnails.Checked;
                kryptonCHKPrecacheThumbnails.Enabled = kryptonCHKShowThumbnails.Checked;
                taggingForm.SetImagePreviews(settings.DisplayImageThumbnails, settings.PreviewSize);
            };

            kryptonCHKFitFileColumnToThumbnails.Enabled = settings.DisplayImageThumbnails;
            kryptonCHKFitFileColumnToThumbnails.Checked = settings.FitFileColumnToThumbnails;
            kryptonCHKFitFileColumnToThumbnails.CheckedChanged += (s, e) => 
            {
                settings.FitFileColumnToThumbnails = kryptonCHKFitFileColumnToThumbnails.Checked;
                taggingForm.SetAutoFitFileColumn(settings.DisplayImageThumbnails, settings.PreviewSize, settings.FitFileColumnToThumbnails);
            };

            kryptonCHKPrecacheThumbnails.Enabled = settings.DisplayImageThumbnails;
            kryptonCHKPrecacheThumbnails.Checked = settings.PrecacheImageThumbnails;
            kryptonCHKPrecacheThumbnails.CheckedChanged += (s, e) =>
            {
                settings.PrecacheImageThumbnails = kryptonCHKPrecacheThumbnails.Checked;
            };

            clrLetterboxColor.Color = settings.LetterboxColor;

            clrSearchReplaceRemove.Color = settings.SearchReplaceRemoveColor;
            clrSearchReplaceInsert.Color = settings.SearchReplaceInsertColor;

            kryptonNUDFileReadThreads.Maximum = Math.Max(Environment.ProcessorCount / 2, 1);
            kryptonNUDFileReadThreads.Value = settings.MaxFileReadThreads;
            kryptonNUDFileReadThreads.ValueChanged += (s, e) => 
            {
                settings.MaxFileReadThreads = (int)kryptonNUDFileReadThreads.Value;
                taggingForm.SetThumbnailLoaderMaxThreadCount(settings.MaxFileReadThreads);
            };

            kryptonNUDWorkerThreads.Maximum = Environment.ProcessorCount;
            kryptonNUDWorkerThreads.Value = settings.MaxWorkerThreads;
            kryptonNUDWorkerThreads.ValueChanged += (s, e) => 
            {
                settings.MaxWorkerThreads = (int)kryptonNUDWorkerThreads.Value;
                taggingForm.SetInterrogatorMaxThreadCount(settings.MaxWorkerThreads);
            };

            KeyDown += (s, e) =>
            {
                if (e.KeyCode == Keys.Escape)
                {
                    e.SuppressKeyPress = true;
                    Visible = false;
                }
            };

            StartPosition = FormStartPosition.CenterParent;
        }

        private async void kryptonBTNSave_Click(object sender, EventArgs e)
        {
            SetAPIStatus(APIStatus.Checking);
            bool success = false;
            string error = null;
            try
            {
                var save = await WebUIAPI.SetOptions(Options.FromInterrogateOptions(kryptonCHKKeepModelsInVRAM.Checked, kryptonTBNumBeams.Value, kryptonTBMinLength.Value, kryptonTBMaxLength.Value, kryptonTBThreshold.Value / 100f, kryptonCHKSortByAlpha.Checked, kryptonCHKUseSpaces.Checked, kryptonCHKEscape.Checked));
                success = save.Success;
                error = save.Error;
                SetAPIStatus(APIStatus.Good);
            }
            catch (Exception ex)
            {
                success = false;
                error = ex.Message;
            }
            finally
            {
                if (!success)
                    SetAPIStatus(APIStatus.Bad, error);
            }
        }

        private async void kryptonBTNLoad_Click(object sender, EventArgs e)
        {
            await LoadOptions();
        }

        private void kryptonBTNResetConfirmationPrompt_Click(object sender, EventArgs e)
        {
            settings.ResetConfirmationPrompts();
        }


        private void clrLetterboxColor_Click(object sender, EventArgs e)
        {
            if (hsl.ShowDialog(clrLetterboxColor.Color, this) == DialogResult.OK)
            {
                clrLetterboxColor.Color = settings.LetterboxColor = hsl.GetHSL().ToColor();
                taggingTookkit.SetImageControlLetterboxColor(clrLetterboxColor.Color);
            }
        }

        private void clrSearchReplaceRemove_Click(object sender, EventArgs e)
        {
            if (hsl.ShowDialog(clrSearchReplaceRemove.Color, this) == DialogResult.OK)
            {
                clrSearchReplaceRemove.Color = settings.SearchReplaceRemoveColor = hsl.GetHSL().ToColor();
            }
        }

        private void clrSearchReplaceInsert_Click(object sender, EventArgs e)
        {
            if (hsl.ShowDialog(clrSearchReplaceInsert.Color, this) == DialogResult.OK)
            {
                clrSearchReplaceInsert.Color = settings.SearchReplaceInsertColor = hsl.GetHSL().ToColor();
            }
        }

        public void SetAPIStatus(APIStatus status, string statusMessage = null)
        {
            if(status != lastStatus)
            {
                lastStatus = status;
                switch (status)
                {
                    case APIStatus.Good:
                        if (string.IsNullOrEmpty(statusMessage))
                            statusMessage = "All good";

                        pbStatus.Image = StableDiffusionTools.Properties.Resources.bullet_green16;
                        kryptonBTNSave.Enabled = true;
                        kryptonBTNLoad.Enabled = true;
                        if(ActiveControl == null && lastActiveControl != null)
                        {
                            ActiveControl = lastActiveControl;
                            lastActiveControl = null;
                        }
                        break;
                    case APIStatus.Bad:
                        if(string.IsNullOrEmpty(statusMessage))
                            statusMessage = "Error";

                        pbStatus.Image = StableDiffusionTools.Properties.Resources.bullet_red16;
                        kryptonBTNSave.Enabled = true;
                        kryptonBTNLoad.Enabled = true;
                        break;
                    case APIStatus.Checking:
                        if (string.IsNullOrEmpty(statusMessage))
                            statusMessage = "Working";

                        pbStatus.Image = StableDiffusionTools.Properties.Resources.bullet_blue16;
                        if(ActiveControl == kryptonBTNLoad || ActiveControl == kryptonBTNSave)
                        {
                            lastActiveControl = ActiveControl;
                            ActiveControl = null;
                        }

                        kryptonBTNSave.Enabled = false;
                        kryptonBTNLoad.Enabled = false;
                        break;
                    case APIStatus.Unknown:
                    default:
                        if (string.IsNullOrEmpty(statusMessage))
                            statusMessage = "Unknown";

                        pbStatus.Image = StableDiffusionTools.Properties.Resources.bullet_black16;
                        break;
                }
            }
            toolTip1.SetToolTip(pbStatus, statusMessage);
        }

        public async Task<bool> LoadOptions()
        {
            SetAPIStatus(APIStatus.Checking);
            loading = true;
            bool success = false;
            string error = null;
            try
            {
                var optionResult = await WebUIAPI.GetOptions();
                success = optionResult.Success;
                error = optionResult.Error;
                if (success)
                {
                    var options = optionResult.Data;

                    if (options.interrogate_keep_models_in_memory.HasValue)
                        kryptonCHKKeepModelsInVRAM.Checked = options.interrogate_keep_models_in_memory.Value;

                    if (options.interrogate_clip_num_beams.HasValue)
                        kryptonTBNumBeams.Value = (int)MathUtil.Clamp(options.interrogate_clip_num_beams.Value, kryptonTBNumBeams.Minimum, kryptonTBNumBeams.Maximum);

                    if (options.interrogate_clip_min_length.HasValue)
                        kryptonTBMinLength.Value = (int)MathUtil.Clamp(options.interrogate_clip_min_length.Value, kryptonTBMinLength.Minimum, kryptonTBMinLength.Maximum);

                    if (options.interrogate_clip_max_length.HasValue)
                        kryptonTBMaxLength.Value = (int)MathUtil.Clamp(options.interrogate_clip_max_length.Value, kryptonTBMaxLength.Minimum, kryptonTBMaxLength.Maximum);

                    if (options.interrogate_deepbooru_score_threshold.HasValue)
                        kryptonTBThreshold.Value = (int)MathUtil.Clamp(options.interrogate_deepbooru_score_threshold.Value * 100, kryptonTBThreshold.Minimum, kryptonTBThreshold.Maximum);

                    if (options.deepbooru_sort_alpha.HasValue)
                        kryptonCHKSortByAlpha.Checked = options.deepbooru_sort_alpha.Value;

                    if (options.deepbooru_use_spaces.HasValue)
                        kryptonCHKUseSpaces.Checked = options.deepbooru_use_spaces.Value;

                    if (options.deepbooru_escape.HasValue)
                        kryptonCHKEscape.Checked = options.deepbooru_escape.Value;

                    SetAPIStatus(APIStatus.Good);
                    FetchedSettings = true;
                }
            }
            catch (Exception ex)
            {
                success = false;
                error = ex.Message;
            }
            finally
            {
                if (!success)
                    SetAPIStatus(APIStatus.Bad, error);

                loading = false;
            }
   
            return success;
        }

        public void BusyChanged(bool busy)
        {
            if (busy)
            {
                kryptonGBTagsList.Enabled = false;
                kryptonGBMultiThreading.Enabled = false;
            }
            else
            {
                kryptonGBTagsList.Enabled = true;
                kryptonGBMultiThreading.Enabled = true;
            }
        }
    }
}
